#include <stdio.h>
#include <monitor.h>
#include <kmalloc.h>
#include <assert.h>

// Initialize monitor.
void monitor_init(monitor_t *mtp, size_t num_cv)
{
    int i;
    assert(num_cv > 0);
    mtp->next_count = 0;
    mtp->cv = NULL;
    sem_init(&(mtp->mutex), 1); // unlocked
    sem_init(&(mtp->next), 0);
    mtp->cv = (condvar_t *)kmalloc(sizeof(condvar_t) * num_cv);
    assert(mtp->cv != NULL);
    for (i = 0; i < num_cv; i++)
    {
        mtp->cv[i].count = 0;
        sem_init(&(mtp->cv[i].sem), 0);
        mtp->cv[i].owner = mtp;
    }
}

// Unlock one of threads waiting on the condition variable.
void cond_signal(condvar_t *cvp)
{
    // LAB7 EXERCISE1: YOUR CODE
    cprintf("cond_signal begin: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
    /*
     *      cond_signal(cv) {
     *          if(cv.count>0) {
     *             mt.next_count ++;
     *             signal(cv.sem);
     *             wait(mt.next);
     *             mt.next_count--;
     *          }
     *       }
     */
    if (cvp->count > 0) //确保有人在阻塞
    {
        cvp->owner->next_count++; //管程只能同时有一个线程在运行，所以要把自己挂起来
        up(&cvp->sem);            //唤醒别人
        down(&cvp->owner->next);  //阻塞自己
        cvp->owner->next_count--; //自己阻塞没了就--
    }
    cprintf("cond_signal end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
}

// Suspend calling thread on a condition variable waiting for condition Atomically unlocks
// mutex and suspends calling thread on conditional variable after waking up locks mutex. Notice: mp is mutex semaphore for monitor's procedures
void cond_wait(condvar_t *cvp)
{
    // LAB7 EXERCISE1: YOUR CODE
    cprintf("cond_wait begin:  cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
    /*
     *         cv.count ++;
     *         if(mt.next_count>0)
     *            signal(mt.next)
     *         else
     *            signal(mt.mutex);
     *         wait(cv.sem);
     *         cv.count --;
     */
    cvp->count++; //等待数++
    if (cvp->owner->next_count > 0)
    { // 如果说别人是因为条件变量阻塞的
        up(&cvp->owner->next);
    }
    else
    { //是不是条件变量阻塞的就是互斥锁阻塞
        up(&cvp->owner->mutex);
    }
    down(&cvp->sem); //阻塞自己
    cvp->count--;    //接触阻塞
    cprintf("cond_wait end:  cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count);
}
